#include "WanP2PDaemon.h"

namespace cm_nat
{
    WanP2PDaemon::WanP2PDaemon()
        :m_mediaSessioin(NULL),
        m_activeLink(NULL),
        m_offerLink(NULL),
        m_selectLink(NULL),
        m_listener(NULL),
        m_activeLinkCheckResult(LINK_CHECK_NULL)
    {

    }

    WanP2PDaemon::~WanP2PDaemon()
    {

    }

    int WanP2PDaemon::setup(std::string username, std::string pwd,std::string server, UInt16 serverPort)
    {
        m_username = username;
        m_password = pwd;
        m_resource = "daemon";
        m_server   = server;
        m_serverPort = serverPort;

        m_xmppClient.registerListener( this );
        m_xmppClient.setup( m_username, m_password, m_resource, m_server, m_serverPort);
        m_xmppClient.connect();

        m_jingleManager.registerListener( this );
        m_jingleManager.setup( m_xmppClient.getClientBase() );

        m_linkPool.setHostIP( IPAddress("192.168.0.128") );
        
        m_linkPool.setup(2, SocketAddress("stunserver.org", 3478) );

        return CM_RES_SUCCESS;
    }

    int WanP2PDaemon::teardown()
    {

        return CM_RES_SUCCESS;
    }

    void WanP2PDaemon::registerListener( WanP2PDaemonListener* p_listener )
    {
        m_listener = p_listener;
    }

    int  WanP2PDaemon::sendCandidate()
    {
        if( !m_offerLink ){
            m_offerLink = m_linkPool.allocateLink();
        }

        if( m_offerLink ){
            m_mediaSessioin->sendCandidate( m_offerLink->getStunReflexAddress() );
        }

        return CM_RES_SUCCESS;
    }

    int WanP2PDaemon::sendCheckConnectionResult( )
    {
        if( m_activeLinkCheckResult == LINK_CHECK_SUCCESS ){
            
            m_mediaSessioin->sendPeerCheckResult( MediaSession::CHECK_RES_SUCCESS, m_activeLink->getPeerReflexAddress() );

        }else{
            SocketAddress sa;
            m_mediaSessioin->sendPeerCheckResult( MediaSession::CHECK_RES_FAIL, sa);
        }
        return CM_RES_SUCCESS;
    }

    int WanP2PDaemon::send(ByteBuffer* data)
    {
        if( m_selectLink ){
            m_selectLink->send( data );
        }

        return CM_RES_SUCCESS;
    }


    //from JingleManagerListener
    void WanP2PDaemon::onSessionInitiate(JingleSession* p_js)
    {
        m_mediaSessioin = (MediaSession*)p_js;
        m_mediaSessioin->registerLisener( this );
    }

    void WanP2PDaemon::onSessionTerminate(JingleSession* p_js)
    {
        std::cout<<"onSessionTerminate\n";
    }


    //from MediaSessionListener
    void WanP2PDaemon::onInitiate( MediaSession* p_session )
    {
        p_session->sendSessionAccept();
        //offer controlled side candidate
        sendCandidate();
    }

    void WanP2PDaemon::onAccept( MediaSession* p_session )
    {
        //do nothing in daemon side
    }

    void  WanP2PDaemon::onCandidate( MediaSession* p_session, Candidate* cand )
    {
        SocketAddress peer( cand->m_rel_addr, cand->m_rel_port );

        if( !m_activeLink ){
            m_activeLink = m_linkPool.allocateLink();
            m_activeLink->registerListener( this );
        }
        m_activeLink->checkConnection( peer );
    }

    void WanP2PDaemon::onCheckResult( MediaSession* p_session, int result )
    {
        //do nothing in daemon side
    }

    void WanP2PDaemon::onSelectCandidate( MediaSession* p_session, Candidate* cand )
    {
        if( cand->m_rel_port == 0 )
            return;

        if( cand->m_rel_port == m_activeLink->getPeerReflexAddress().port() ){
            m_selectLink = m_activeLink;
            m_activeLink = NULL;
        }else{
            m_selectLink = m_offerLink;
            m_offerLink = NULL;
        }

        if( m_selectLink ){
            SocketAddress peer( cand->m_ip, cand->m_port );
            m_selectLink->setPeerAddress( peer );
            m_selectLink->registerListener( this );
        }

        poco_debug(g_log_nat, "WanP2PDaemon::onSelectCandidate");
    }

    //from IceLinkListener
    void WanP2PDaemon::onReceive(IceLink* link, ByteBuffer* p_data)
    {
        poco_debug(g_log_nat,"WanP2PDaemon::onReceive");

        if( m_listener ){
            m_listener->onReceive( this, p_data );
        }else{
            SocketAddress* p_sa = (SocketAddress*)p_data->getData();
            delete p_sa;
            p_data->decreaseRef();
        }
    }

    void WanP2PDaemon::onLinkState( IceLink* link, int state )
    {
        if( link == m_activeLink ){
            if( state == IceLink::STATE_KEEP_PEER_CHECK ){
                m_activeLinkCheckResult = LINK_CHECK_SUCCESS;
            }else{
                m_activeLinkCheckResult = LINK_CHECK_FAIL;
            }
            sendCheckConnectionResult();
        }

        poco_debug(g_log_nat,"WanP2PDaemon::onState() active link check connection success");
        
    }

    //XMPPClientListener
    void WanP2PDaemon::onConnect( XMPPClient* client )
    {

    }

    void WanP2PDaemon::onDisconnect( XMPPClient* client )
    {

    }

}